home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
ab20
/
unarced
/
utilities
/
emulators
/
apple][
/
disk.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-17
|
8KB
|
373 lines
/*
* a2, an Apple II emulator in C
* (c) Copyright 1990 by Rich Skrenta
*
* Command line interface written by Tom Markson
*
* Distribution agreement:
*
* You may freely copy or redistribute this software, so long
* as there is no profit made from its use, sale, trade or
* reproduction. You may not change this copyright notice,
* and it must be included prominently in any copy made.
*
* Send emulator related mail to: skrenta@blekko.commodore.com
* skrenta@blekko.uucp
*/
#include <stdio.h>
#include "a2.h"
#define GAP 0x7F; /* data gap byte */
/*
* 4 by 4 nibble encoding macros
*/
#define nib1(a) (((a) >> 1) | 0xAA)
#define nib2(a) ((a) | 0xAA)
#define denib(a,b) (((((a) & 0x55) << 1) & 0xFF) | ((b) & 0x55))
int cur_track[2] = {0, 0};
int sect_pos[2]; /* current sector within track */
extern unsigned char tab1[]; /* For nibblizing. At end of this file */
extern unsigned char tab2[]; /* Disk byte translation table. */
extern unsigned char phys[]; /* DOS 3.3 to physical sector mapping */
unsigned char sect_buf[2][1024];
unsigned char *sectp = NULL;
unsigned char *sect_point[2] = {NULL, NULL};
unsigned char write_reg; /* write data register */
int write_mode = FALSE;
unsigned char
disk_ref(a, n)
unsigned short a;
unsigned char n;
{
switch (a) {
case 0xC0E0: /* Phase 0 off */
case 0xC0E1: /* Phase 0 on */
case 0xC0E2: /* Phase 1 off */
case 0xC0E3: /* Phase 1 on */
case 0xC0E4: /* Phase 2 off */
case 0xC0E5: /* Phase 2 on */
case 0xC0E6: /* Phase 3 off */
case 0xC0E7: /* Phase 3 on */
step_motor(a);
break;
case 0xC0E8: /* Drive off */
break;
case 0xC0E9: /* Drive on */
break;
case 0xC0EA: /* Select drive 1 */
sect_point[drive] = sectp;
drive = 0;
sectp = sect_point[0];
break;
case 0xC0EB: /* Select drive 2 */
sect_point[drive] = sectp;
drive = 1;
sectp = sect_point[1];
break;
case 0xC0EC: /* Shift data register */
if (disk[drive] < 0)
return(0xFF);
if (write_mode) {
raw_disk_write();
return(0);
}
if (sectp == NULL || *sectp == '\0') {
sect_pos[drive]--;
if (sect_pos[drive] < 0)
sect_pos[drive] = 15;
setup_sector(cur_track[drive], sect_pos[drive]);
}
return(*sectp++);
case 0xC0ED: /* Load data register */
write_reg = n;
break;
case 0xC0EE: /* Read mode */
write_mode = FALSE;
return(write_prot[drive] ? 0xFF : 0);
break;
case 0xC0EF: /* Write mode */
write_mode = TRUE;
break;
}
return(0);
}
/*
* Determine what track the disk head is over by watching toggles to
* the four stepper motor magnets.
*/
step_motor(a)
unsigned short a;
{
static int mag[2][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}},
pmag[2][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}}, /* previous */
ppmag[2][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}}, /* previous previous */
pnum[2] = {0, 0},
ppnum[2] = {0, 0},
track_pos[2] = {0, 0};
static int prev_track[2] = {0, 0};
int magnet_number;
a &= 7;
magnet_number = a >> 1;
ppmag[drive][ppnum[drive]] = pmag[drive][ppnum[drive]];
ppnum[drive] = pnum[drive];
pmag[drive][pnum[drive]] = mag[drive][pnum[drive]];
pnum[drive] = magnet_number;
if ((a & 1) == 0)
mag[drive][magnet_number] = FALSE;
else {
if (ppmag[drive][(magnet_number + 1) & 3]) {
track_pos[drive]--;
if (track_pos[drive] < 0) {
track_pos[drive] = 0;
if (drive)
info("recal d2");
else
info("recal");
}
}
if (ppmag[drive][(magnet_number - 1) & 3]) {
track_pos[drive]++;
if (track_pos[drive] > 140)
track_pos[drive] = 140;
}
mag[drive][magnet_number] = TRUE;
}
cur_track[drive] = (track_pos[drive] + 1) / 2;
if (cur_track[drive] != prev_track[drive]) {
#if 0
sprintf(s, "step to %d%s", cur_track[drive],
drive ? " d2" : "");
info(s);
#endif
sectp[drive] = NULL; /* recompute sector if head moves */
sect_pos[drive] = 0;
prev_track[drive] = cur_track[drive];
}
}
setup_sector(track, sector)
int track;
int sector;
{
int checksum;
int physical_sector;
char s[50];
int i;
physical_sector = phys[sector];
sprintf(s, "raw t=%d s=%d%s", track, sector, drive ? " d2" : "");
info(s);
sectp = sect_buf[drive];
for (i = 0; i < 16; i++)
*sectp++ = GAP;
*sectp++ = 0xD5; /* address header */
*sectp++ = 0xAA;
*sectp++ = 0x96;
*sectp++ = 0xFF; /* disk volume 254 */
*sectp++ = 0xFE;
*sectp++ = nib1(track);
*sectp++ = nib2(track);
*sectp++ = nib1(physical_sector);
*sectp++ = nib2(physical_sector);
checksum = 254 ^ track ^ physical_sector;
*sectp++ = nib1(checksum);
*sectp++ = nib2(checksum);
*sectp++ = 0xDE; /* address trailer */
*sectp++ = 0xAA;
for (i = 0; i < 8; i++)
*sectp++ = GAP;
*sectp++ = 0xD5; /* data header */
*sectp++ = 0xAA;
*sectp++ = 0xAD;
encode_data(track, sector); /* nibblized data */
*sectp++ = 0xDE; /* data trailer */
*sectp++ = 0xAA;
*sectp++ = 0xEB;
*sectp = '\0'; /* ending mark for our use */
sectp = sect_buf[drive]; /* start reading at beginning */
}
/*
* Take a normal 256 byte sector and nibblize it into 342 bytes
* Checksum it with itself; this yields one more byte.
* Translate the resulting 343 bytes into "disk bytes".
* Insert them into the sector buffer.
*
* See a reference such as _Beneath Apple Prodos_ for an explanation
* of why & how this is done.
*/
encode_data(track, sector)
int track;
int sector;
{
unsigned char buf[344];
unsigned char *one;
unsigned char *bump;
unsigned char *two;
unsigned char *three;
unsigned char *dest;
int i;
read_disk(track, sector, &buf[86]);
buf[342] = 0;
buf[343] = 0;
dest = buf;
one = &buf[86];
two = &buf[86 + 0x56];
bump = two;
three = &buf[86 + 0xAC];
do {
i = (*one++ & 0x03) |
((*two++ & 0x03) << 2) | ((*three++ & 0x03) << 4);
*dest++ = tab1[i];
} while (one != bump);
sectp[0] = buf[0];
for (i = 1; i <= 342; i++)
sectp[i] = buf[i - 1] ^ buf[i];
for (i = 0; i <= 342; i++)
sectp[i] = tab2[ sectp[i] >> 2 ];
sectp = §p[343];
}
raw_disk_write() {
printf("raw write %.2X\n", write_reg);
}
read_disk(track, sector, buf)
int track;
int sector;
unsigned char *buf;
{
long block;
block = track * 16 + sector;
lseek(disk[drive], block * 256, 0);
if (read(disk[drive], buf, 256) != 256)
perror("bad read");
}
write_disk(track, sector, buf)
int track;
int sector;
unsigned char *buf;
{
long block;
block = track * 16 + sector;
lseek(disk[drive], block * 256, 0);
if (write(disk[drive], buf, 256) != 256)
perror("bad write");
}
/*
* Helps with the bit fiddling necessary to extract the bottom
* two bits during the 256 - 342 byte nibblize.
*/
unsigned char tab1[] = {
0x00, 0x08, 0x04, 0x0C, 0x20, 0x28, 0x24, 0x2C,
0x10, 0x18, 0x14, 0x1C, 0x30, 0x38, 0x34, 0x3C,
0x80, 0x88, 0x84, 0x8C, 0xA0, 0xA8, 0xA4, 0xAC,
0x90, 0x98, 0x94, 0x9C, 0xB0, 0xB8, 0xB4, 0xBC,
0x40, 0x48, 0x44, 0x4C, 0x60, 0x68, 0x64, 0x6C,
0x50, 0x58, 0x54, 0x5C, 0x70, 0x78, 0x74, 0x7C,
0xC0, 0xC8, 0xC4, 0xCC, 0xE0, 0xE8, 0xE4, 0xEC,
0xD0, 0xD8, 0xD4, 0xDC, 0xF0, 0xF8, 0xF4, 0xFC,
};
/*
* Translates to "disk bytes"
*/
unsigned char tab2[] = {
0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6,
0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3,
0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC,
0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3,
0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE,
0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC,
0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
};
/*
* Dos 3.3 to physical sector conversion
*/
unsigned char phys[] = {
0x00, 0x0D, 0x0B, 0x09, 0x07, 0x05, 0x03, 0x01,
0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, 0x0F,
};